package br.art.late.openenvironment.main;

import geomerative.RFont;
import geomerative.RG;
import geomerative.RPoint;
import geomerative.RShape;

import java.util.ArrayList;

import processing.core.PApplet;
import processing.core.PGraphics;
import br.art.late.openenvironment.boids.BoidsFlock;
import br.art.late.openenvironment.boids.FpsCounter;
import br.art.late.openenvironment.boids.Obj;
import codeanticode.syphon.SyphonServer;

public class OpenEnvironment extends PApplet {

	private PGraphics canvas;
	SyphonServer server;
	private ArrayList foodList;
	private ArrayList obstList;
	int foodNbr, obstNbr, boidsNbr;
	boolean displayAura, displayPerception;
	boolean changeObstAura, changeFoodAura;
	float obstAuraFactor, foodAuraFactor;
	private BoidsFlock boids;
	FpsCounter fps;
	boolean saveFrame = false;
	RFont f;
	RShape grp;
	RPoint[] points;

	public void setup() {
		// canvas SESI size
		size(214, 168);

		// size(1280, 768);
		frameRate(25);
		smooth();
		
		setupRG();
		try {

			//setupSyphon();
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("here");
			e.printStackTrace();
		}
		noCursor();

		// initialize obstacles
		setObstList(new ArrayList());
		obstNbr = 10;
		obstAuraFactor = 3;
		// initialize food
		setFoodList(new ArrayList());
		foodNbr = 10;
		foodAuraFactor = 10;
		// initialize boids
		setBoids(new BoidsFlock(this));
		boidsNbr = 400;

		// initialize controls
		// controlsInit();
		// fps = new FpsCounter(width - 56, 42);

		// create foods
		for (int i = 0; i < foodNbr; i++) {
			getFoodList().add(new Obj(this));
			Obj o = (Obj) getFoodList().get(i);
			o.setAura(o.getRad() * foodAuraFactor);
		}
		// create obstacles
		for (int i = 0; i < obstNbr; i++) {
			// obstList.add(new Obj());
			// Obj o = (Obj)obstList.get(i);
			// o.aura = o.rad * obstAuraFactor;
		}
		// create boids
		for (int i = 0; i < boidsNbr; i++) {
			getBoids().add();
		}
	}

	public void setupRG() {
		// VERY IMPORTANT: Allways initialize the library in the setup
		RG.init(this);

		// Load the font file we want to use (the file must be in the data
		// folder in the sketch floder), with the size 60 and the alignment
		// CENTER
		// grp = RG.getText("Open Environment", "FreeSans.ttf", 72, CENTER);

	}

	public void setupSyphon() {
		canvas = createGraphics(1024, 768, P2D);
		canvas.fill(0, 255, 51);

		// Create syphon server to send frames out.
		server = new SyphonServer(this, "Open Environment");
	}

	public void draw() {

		//canvas.beginDraw();
		background(0);

		// draw details (controls manipulation)
		// if(displayPerception) boids.displayPerception();
		// if(displayAura) boids.displayAura();
		// if(changeObstAura) changeObjAura(obstList, obstAuraFactor, 100, 100,
		// 100);
		// if(changeFoodAura) changeObjAura(foodList, foodAuraFactor, 100, 255,
		// 100);

		// draw food
		for (int i = 0; i < getFoodList().size(); i++) {
			Obj f = (Obj) getFoodList().get(i);
			f.display(120, 255, 120);
		}
		// draw obstacles
		for (int i = 0; i < getObstList().size(); i++) {
			Obj o = (Obj) getObstList().get(i);
			o.display();
		}

		// hide control zone background and draw fps
		// fill(255);
		// noStroke();
		// rect(0, 0, width, 50);
		// fps.display();

		// compute
		getBoids().update();

		// draw boids and zone border
		getBoids().display();
		// boids.zone.border(150);

		//canvas.endDraw();
		//image(canvas, 0, 0);

		if (saveFrame)
			saveFrame("frames/openEnvironment-######.png.png");
		//server.sendImage(canvas);
	}

	public void mapTextToFood(String text) {
		RG.setPolygonizer(RG.UNIFORMSTEP);
		RG.setPolygonizerStep(0f);
		// translate(width/2, height/2);
		int posX = (int) random(200, width - 200);
		int posY = (int) random(150, height - 150);
		grp = RG.getText(text, "../res/FreeSans.ttf", 72, CENTER);
		points = grp.getPoints();
		println(points.length);
		// If there are any points
		if (points != null) {
			noFill();
			stroke(0, 200, 0);
			// beginShape();
			// for (int i=0; i<points.length; i++) {
			// //foodList.add(new Obj((int)points[i].x, (int)points[i].y));
			// //vertex(points[i].x, points[i].y);
			// }
			// endShape();

			fill(0);
			stroke(0);
			for (int i = 0; i < points.length; i++) {
				getFoodList().add(
						new Obj((int) points[i].x + posX, (int) points[i].y
								+ posY, this));
				// ellipse(points[i].x, points[i].y, 5, 5);
			}
		}
	}

	public void mousePressed() {
		// check if clic is in sim zone
		if (getBoids().zone.isIn(mouseX, mouseY)) {
			// add food on left clic
			if (mouseButton == LEFT) {
				// foodList.add(new Obj(mouseX, mouseY));
				float text = random(3);
				if (text < 1)
					mapTextToFood("OpenEnvironment");
				else if (text > 1 && text < 2)
					mapTextToFood("Interactive");
				else if (text > 2)
					mapTextToFood("Artwork");
			}
			// add obst on right clic
			else if (mouseButton == RIGHT) {
				getObstList().add(new Obj(mouseX, mouseY, this));
			}
			// delete things with middle clic
			else if (mouseButton == CENTER) {
				// delete food if mouse is on it
				for (int i = 0; i < getFoodList().size(); i++) {
					Obj o = (Obj) getFoodList().get(i);
					if (dist(o.getPos().x, o.getPos().y, mouseX, mouseY) < o
							.getRad()) {
						getFoodList().remove(o);
						break;
					}
				}
				// delete obstacle if mouse is on it
				for (int i = 0; i < getObstList().size(); i++) {
					Obj o = (Obj) getObstList().get(i);
					if (dist(o.getPos().x, o.getPos().y, mouseX, mouseY) < o
							.getRad()) {
						getObstList().remove(o);
						break;
					}
				}
			}
		}
	}

	// stop displaying details on mouse releasing
	public void mouseReleased() {
		displayAura = false;
		displayPerception = false;
		changeFoodAura = false;
		changeObstAura = false;
	}

	// reset on SPACE press
	public void keyPressed() {
		if (key == ' ')
			setup();
	}

	// change aura value and display it (controls manipulation)
	public void changeObjAura(ArrayList l, float f, int r, int g, int b) {
		fill(r, g, b, 20);
		stroke(r, g, b, 50);
		for (int i = 0; i < l.size(); i++) {
			Obj o = (Obj) l.get(i);
			o.setAura(o.getRad() * f);
			ellipse(o.getPos().x, o.getPos().y, o.getAura() * 2,
					o.getAura() * 2);
		}
	}

	static public void main(String[] passedArgs) {
		String[] appletArgs = new String[] { "OpenEnvironment" };
		if (passedArgs != null) {
			PApplet.main(concat(appletArgs, passedArgs));
		} else {
			PApplet.main(appletArgs);
		}
	}

	public BoidsFlock getBoids() {
		return boids;
	}

	public void setBoids(BoidsFlock boids) {
		this.boids = boids;
	}

	/**
	 * @return the foodList
	 */
	public ArrayList getFoodList() {
		return foodList;
	}

	/**
	 * @param foodList
	 *            the foodList to set
	 */
	public void setFoodList(ArrayList foodList) {
		this.foodList = foodList;
	}

	/**
	 * @return the obstList
	 */
	public ArrayList getObstList() {
		return obstList;
	}

	/**
	 * @param obstList
	 *            the obstList to set
	 */
	public void setObstList(ArrayList obstList) {
		this.obstList = obstList;
	}

	/**
	 * @return the canvas
	 */
	public OpenEnvironment getCanvas() {
		return this;
	}

	/**
	 * @param canvas
	 *            the canvas to set
	 */
	private void setCanvas(PGraphics canvas) {
		this.canvas = canvas;
	}
}
